﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Enter.DataCommon;

namespace Enter.DataProxy.DbConnector.Helpers
{
	/// <summary>
	/// 执行sql语句，提供简单快速使用ADO.NET的方法。
	/// </summary>
	public abstract class DbHelper : IParamCollectionProvider
	{
		#region

		//public abstract SqlBuilder SqlBuilder { get; }

		#endregion

		/// <summary>
		/// 
		/// </summary>
		public DbHelper()
		{
		}

		#region CreateParamCollection

		/// <summary>
		/// 创建一个SQL语句参数集合
		/// </summary>
		/// <returns>SQL语句参数集合</returns>
		public abstract ParameterCollection CreateParamCollection();

		/// <summary>
		/// 创建一个SQL语句参数集合
		/// </summary>
		/// <param name="capacity">集合每次分配空间的增量大小</param>
		/// <returns>SQL语句参数集合</returns>
		public abstract ParameterCollection CreateParamCollection(int capacity);

		#endregion

		#region ExecuteCommand

		protected internal abstract DataSet ExecuteDataSet(CommandType cmdType, string cmdText, ParameterCollection parameters);

		protected internal abstract int ExecuteNonQuery(CommandType cmdType, string cmdText, ParameterCollection parameters, bool mustTransaction);

		protected internal abstract IDataReader ExecuteReader(CommandType cmdType, string cmdText, ParameterCollection parameters);

		protected internal abstract object ExecuteScalar(CommandType cmdType, string cmdText, ParameterCollection parameters, bool mustTransaction);


		#endregion

		#region Execute

		///// <summary>
		///// 在只写库执行一条sql语句，不返回任何结果集。(注：这是一个事务安全的方法)
		///// </summary>
		///// <param name="batch">sql语句批次</param>
		///// <returns>受影响的行数</returns>
		//public virtual int Execute(BatchSQL batch)
		//{
		//    StringBuilder sql = new StringBuilder();
		//    foreach (string sqlStatment in batch)
		//    {
		//        sql.AppendLine(sqlStatment);
		//    }
		//    return ExecuteNonQuery(CommandType.Text, sql.ToString(), batch.Parameters, true);
		//}

		/// <summary>
		/// 执行一条sql语句，返回 T 类型的 IList集合。
		/// </summary>
		/// <typeparam name="T">集合中的类型，必须是DataMap/DataReadonly的子类。</typeparam>
		/// <param name="sql">一条sql语句</param>
		/// <returns>T 类型的 IList集合</returns>
		public virtual IList<T> Execute<T>(string sql) where T : MapSet, new()
		{
			return Execute<T>(sql, (ParameterCollection)null);
		}

		/// <summary>
		/// 执行一条sql语句，返回 T 类型的 IList集合。
		/// </summary>
		/// <typeparam name="T">集合中的类型，必须是DataMap/DataReadonly的子类。</typeparam>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数,参数可以为空。</param>
		/// <returns>T 类型的 IList集合</returns>
		public virtual IList<T> Execute<T>(string sql, ParameterCollection parameters) where T : MapSet, new()
		{
			using (IDataReader reader = ExecuteReader(CommandType.Text, sql, parameters))
			{
				return reader.ToList<T>();
			}
		}

		/// <summary>
		/// 执行一条sql语句，返回 T 类型的 IList集合。
		/// </summary>
		/// <typeparam name="T">集合中的类型，必须是DataMap/DataReadonly的子类。</typeparam>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数,参数可以为空。</param>
		/// <returns>T 类型的 IList集合</returns>
		public virtual IList<T> Execute<T>(string sql, params object[] parameters) where T : MapSet, new()
		{
			ParameterCollection para = CreateParamCollection(parameters.Length);
			sql = string.Format(sql, para.Fill(parameters));

			return Execute<T>(sql, para);
		}

		#endregion

		#region ExecuteScalar<T>

		/// <summary>
		/// 在只读库执行一条sql语句，返回一个标值。
		/// </summary>
		/// <typeparam name="T">将sql返回的值转换成 T 并返回</typeparam>
		/// <param name="sql">一条sql语句</param>
		/// <returns>如果是转换失败将抛出异常，表示sql返回的数据不符开发人员指定的类型。所以开发人员需要自己把握异常处理。</returns>
		public virtual T ExecuteScalar<T>(string sql)
		{
			return ExecuteScalar<T>(sql, (ParameterCollection)null);
		}

		/// <summary>
		/// 在只读库执行一条sql语句，返回一个标值。
		/// </summary>
		/// <typeparam name="T">将sql返回的值转换成 T 并返回</typeparam>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql参数集合</param>
		/// <returns>如果是转换失败将抛出异常，表示sql返回的数据不符开发人员指定的类型。所以开发人员需要自己把握异常处理。</returns>
		public virtual T ExecuteScalar<T>(string sql, ParameterCollection parameters)
		{
			object val = ExecuteScalar(CommandType.Text, sql, parameters, false);
            return val.To<T>();
		}

		/// <summary>
		/// 在只读库执行一条sql语句，返回一个标值。
		/// </summary>
		/// <typeparam name="T">将sql返回的值转换成 T 并返回</typeparam>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql参数集合</param>
		/// <returns>如果是转换失败将抛出异常，表示sql返回的数据不符开发人员指定的类型。所以开发人员需要自己把握异常处理。</returns>
		public virtual T ExecuteScalar<T>(string sql, params object[] parameters)
		{
			ParameterCollection para = CreateParamCollection(parameters.Length);
			sql = string.Format(sql, para.Fill(parameters));

			return ExecuteScalar<T>(sql, para);
		}

		#endregion

		#region ExecuteNonQuery

		/// <summary>
		/// 执行一条sql语句，不返回结果集。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <returns></returns>
		public virtual int ExecuteNonQuery(string sql)
		{
			return ExecuteNonQuery(CommandType.Text, sql, (ParameterCollection)null, false);
		}

		/// <summary>
		/// 执行一条sql语句，不返回结果集。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数</param>
		/// <returns></returns>
		public virtual int ExecuteNonQuery(string sql, ParameterCollection parameters)
		{
			return ExecuteNonQuery(CommandType.Text, sql, parameters, false);
		}

		/// <summary>
		/// 执行一条sql语句，不返回结果集。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数,参数可以为空。</param>
		/// <returns></returns>
		public virtual int ExecuteNonQuery(string sql, params object[] parameters)
		{
			ParameterCollection para = CreateParamCollection(parameters.Length);
			sql = string.Format(sql, para.Fill(parameters));

			return ExecuteNonQuery(CommandType.Text, sql, para, false);
		}

		#endregion

		#region ExecuteReader

		/// <summary>
		/// 执行一条sql语句，返回一个IDataReader。注：使用完以后一定要手动关闭IDataReader。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <returns></returns>
		public virtual IDataReader ExecuteReader(string sql)
		{
			return ExecuteReader(CommandType.Text, sql, (ParameterCollection)null);
		}

		/// <summary>
		/// 执行一条sql语句，返回一个IDataReader。注：使用完以后一定要手动关闭IDataReader。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数</param>
		/// <returns></returns>
		public virtual IDataReader ExecuteReader(string sql, ParameterCollection parameters)
		{
			return ExecuteReader(CommandType.Text, sql, parameters);
		}

		/// <summary>
		/// 执行一条sql语句，返回一个IDataReader。注：使用完以后一定要手动关闭IDataReader。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数,参数可以为空。</param>
		/// <returns></returns>
		public virtual IDataReader ExecuteReader(string sql, params object[] parameters)
		{
			ParameterCollection para = CreateParamCollection(parameters.Length);
			sql = string.Format(sql, para.Fill(parameters));

			return ExecuteReader(CommandType.Text, sql, para);
		}

		#endregion

		#region ExecuteTable

		/// <summary>
		/// 执行一条sql语句，返回一个DataTable。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <returns>返回一个DataTable。注：此DataTable是绝对不会为空，所以接收的一方不需要做任何是否为空的判断。</returns>
		public virtual DataTable ExecuteTable(string sql)
		{
			return ExecuteDataSet(CommandType.Text, sql, (ParameterCollection)null).First();
		}

		/// <summary>
		/// 执行一条sql语句，返回一个DataTable。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数,参数可以为空。</param>
		/// <returns>返回一个DataTable。注：此DataTable是绝对不会为空，所以接收的一方不需要做任何是否为空的判断。</returns>
		public virtual DataTable ExecuteTable(string sql, ParameterCollection parameters)
		{
			return ExecuteDataSet(CommandType.Text, sql, parameters).First();
		}

		/// <summary>
		/// 执行一条sql语句，返回一个DataTable。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数,参数可以为空。</param>
		/// <returns>返回一个DataTable。注：此DataTable是绝对不会为空，所以接收的一方不需要做任何是否为空的判断。</returns>
		public virtual DataTable ExecuteTable(string sql, params object[] parameters)
		{
			ParameterCollection para = CreateParamCollection(parameters.Length);
			sql = string.Format(sql, para.Fill(parameters));

			return ExecuteDataSet(CommandType.Text, sql, para).First();
		}

		#endregion

		#region ExecuteDataSet

		/// <summary>
		/// 执行一条sql语句，返回一个DataSet。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <returns>返回一个DataSet。注：此DataSet是绝对不会为空，所以接收的一方不需要做任何是否为空的判断。</returns>
		public virtual DataSet ExecuteDataSet(string sql)
		{
			return ExecuteDataSet(CommandType.Text, sql, (ParameterCollection)null);
		}

		/// <summary>
		/// 执行一条sql语句，返回一个DataSet。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数,参数可以为空。</param>
		/// <returns>返回一个DataSet。注：此DataSet是绝对不会为空，所以接收的一方不需要做任何是否为空的判断。</returns>
		public virtual DataSet ExecuteDataSet(string sql, ParameterCollection parameters)
		{
			return ExecuteDataSet(CommandType.Text, sql, parameters);
		}

		/// <summary>
		/// 执行一条sql语句，返回一个DataSet。
		/// </summary>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数,参数可以为空。</param>
		/// <returns>返回一个DataSet。注：此DataSet是绝对不会为空，所以接收的一方不需要做任何是否为空的判断。</returns>
		public virtual DataSet ExecuteDataSet(string sql, params object[] parameters)
		{
			ParameterCollection para = CreateParamCollection(parameters.Length);
			sql = string.Format(sql, para.Fill(parameters));

			return ExecuteDataSet(CommandType.Text, sql, para);
		}

		///// <summary>
		///// 执行一个sql批处理，返回一个DataSet。
		///// </summary>
		///// <param name="batch"></param>
		///// <returns></returns>
		//public virtual DataSet ExecuteDataSet(BatchSQL batch)
		//{
		//    StringBuilder sql = new StringBuilder();
		//    foreach (string sqlStatment in batch)
		//    {
		//        sql.AppendLine(sqlStatment);
		//    }
		//    return ExecuteDataSet(CommandType.Text, sql.ToString(), (ParameterCollection)null);
		//}

		#endregion

		#region ExecuteFirstColumn<T>

		/// <summary>
		/// 执行一条sql语句，返回DataTable中第一列的值。
		/// </summary>
		/// <typeparam name="T">集合中的类型，必须是DataMap/DataReadonly的子类。</typeparam>
		/// <param name="sql">一条sql语句</param>
		/// <returns>T 类型的 IList集合</returns>
		public virtual IList<T> ExecuteFirstColumn<T>(string sql)
		{
			return ExecuteFirstColumn<T>(sql, (ParameterCollection)null);
		}

		/// <summary>
		/// 执行一条sql语句，返回DataTable中第一列的值。
		/// </summary>
		/// <typeparam name="T">集合中的类型，必须是DataMap/DataReadonly的子类。</typeparam>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数,参数可以为空。</param>
		/// <returns>T 类型的 IList集合</returns>
		public virtual IList<T> ExecuteFirstColumn<T>(string sql, ParameterCollection parameters)
		{
			using (IDataReader read = ExecuteReader(CommandType.Text, sql, parameters))
			{
				IList<T> list = new List<T>(read.RecordsAffected < 4 ? 4 : read.RecordsAffected);
				while (read.Read())
				{
					list.Add((T)read[0]);
				}
				return list;
			}
		}

		/// <summary>
		/// 执行一条sql语句，返回DataTable中第一列的值。
		/// </summary>
		/// <typeparam name="T">集合中的类型，必须是DataMap/DataReadonly的子类。</typeparam>
		/// <param name="sql">一条sql语句</param>
		/// <param name="parameters">sql语句的参数,参数可以为空。</param>
		/// <returns>T 类型的 IList集合</returns>
		public virtual IList<T> ExecuteFirstColumn<T>(string sql, params object[] parameters)
		{
			ParameterCollection para = CreateParamCollection(parameters.Length);
			sql = string.Format(sql, para.Fill(parameters));
			//
			return ExecuteFirstColumn<T>(sql, para);
		}

		#endregion

		#region ExecProcdure

		/// <summary>
		/// 执行一个存储过程，返回 T 类型的列表。
		/// </summary>
		/// <typeparam name="T">集合中的类型，必须是DataMap/DataReadonly的子类。</typeparam>
		/// <param name="spName">存储过程名称</param>
		/// <param name="parameters">存储过程的参数</param>
		/// <remarks>
		/// <para>注：请小心使用此方法，如果你的存储过程返回的结果集合包含了返回值，DataSet中的第0个Datable的值将会是它，所以会使得转换实体对象发生异常。</para>
		/// <para>或者存储过程中没有包含返回值或查询结果集合那么DataSet中的DataTable数量将为0也会发生异常。使用此方法前请确认存储过程。</para>
		/// </remarks>
		/// <returns>T 类型的 IList集合</returns>
		public IList<T> ExecProcdure<T>(string spName, ParameterCollection parameters) where T : MapSet, new()
		{
			using (IDataReader read = ExecuteReader(CommandType.StoredProcedure, spName, parameters))
			{
				return read.ToList<T>();
			}
		}

		/// <summary>
		/// 执行一个存储过程，不返回结果集。
		/// </summary>
		/// <param name="spName">存储过程名称</param>
		/// <param name="parameters">存储过程的参数</param>
		/// <returns>影响到的数据行数</returns>
		public int ExecProcdureNonQuery(string spName, ParameterCollection parameters)
		{
			return ExecuteNonQuery(CommandType.StoredProcedure, spName, parameters, false);
		}

		/// <summary>
		/// 执行一个存储过程，返回一个DataSet。
		/// </summary>
		/// <param name="spName">存储过程名称</param>
		/// <param name="parameters">存储过程的参数</param>
		/// <returns>返回一个不为空的DataSet</returns>
		public DataSet ExecProcdureDataSet(string spName, ParameterCollection parameters)
		{
			return ExecuteDataSet(CommandType.StoredProcedure, spName, parameters);
		}

		#endregion

		#region ExecutePage

		/// <summary>
		/// sql 自动分页程序
		/// </summary>
		/// <param name="commandText"></param>
		/// <param name="parameters"></param>
		/// <returns></returns>
		public virtual DataPage ExecutePage(string commandText, ParameterCollection parameters)
		{
			DataPage result = new DataPage();
			
			DataPageSql pagesql = ExecutePageSqlTxt(commandText,parameters);
			if (pagesql.IsSuccess)
			{
				result.IsSuccess = true;
				try
				{
					DataSet ds = ExecuteDataSet(CommandType.Text, pagesql.PageSql, pagesql.parameters);
					result.DataValue = ds.Tables[1];
					result.RowsCount = ds.Tables[0].Rows[0][0].To<int>();
				}
				catch
				{
					result.IsSuccess = false;
				}
			}


			return result;
			
		}

		public virtual IList<T> ExecutePage<T>(string commandText, ParameterCollection parameters) where T : MapSet, new()
		{
			IList<T> result =new List<T>(0);
			DataPage dp = ExecutePage(commandText, parameters);
			if (dp.IsSuccess)
			{
				result = dp.ShowEntity<T>();
			}
			return result;
		}

		protected virtual DataPageSql ExecutePageSqlTxt(string commandText, ParameterCollection parameters)
		{
			DataPageSql result = new DataPageSql();
			string name = string.Empty;
			foreach (var para in parameters)
			{
				name = para.ParameterName.ToLower().Replace(parameters.Prefix, "");
				switch (name)
				{
					case "order":
						result.order = para.Value.To<string>();
						break;
					case "pageid":
						result.pageid = para.Value.To<int>();
						break;
					case "pagesize":
						result.pagesize = para.Value.To<int>();
						break;
				}
			}
			if (!string.IsNullOrEmpty(result.order) && result.pageid > 0 && result.pagesize > 0)
			{
				result.IsSuccess = true;
			}
			return result;
		}

		#endregion
	}
}
